home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / dos6mm.zip / XMS2EMS.ASM < prev    next >
Assembly Source File  |  1993-03-31  |  63KB  |  1,354 lines

  1. ;****************************************************************************
  2. ; XMS2EMS is an EMS 3.2 expanded memory manager (EMM) that uses extended
  3. ; memory managed by HIMEM.SYS to store data written to expanded memory.
  4. ; Its syntax is:
  5. ;
  6. ;       DEVICE=XMS2EMS.SYS [memory] [/H=nnn]
  7. ;
  8. ; where "memory" is amount of expanded memory to be created (in kilobytes)
  9. ; and "nnn" is the number of handles desired (range=8 to 255, default=64).
  10. ; If the amount of expanded memory to be made available to the system is not
  11. ; specified, XMS2EMS defaults to 256K. The maximum that XMS2EMS supports is
  12. ; 8192 (8MB), the minimum 256K.
  13. ;
  14. ; DEVELOPER'S NOTES:
  15. ; ******************
  16. ;
  17. ; To manage EMS memory, XMS2EMS maintains a table called PAGE_TABLE that
  18. ; contains one entry for each 16K EMS page. Each entry is structured as
  19. ; follows:
  20. ;
  21. ;       HANDLE          DW      ?
  22. ;       LOGICAL_PAGE    DW      ?
  23. ;
  24. ; HANDLE is the number of the handle that owns the page. A value of FFFFh
  25. ; indicates the page is free. LOGICAL_PAGE is the logical page number for
  26. ; the range of memory assigned to the handle. It is only meaningful if
  27. ; the HANDLE field contains a valid (non-FFFFh) value.
  28. ;
  29. ; XMS2EMS also contains one table that holds information about handles.
  30. ; HNDL_TABLE contains one 1-byte entry for each handle supported. If the
  31. ; byte that corresponds to a handle is 0, then the handle is unassigned.
  32. ; This isn't strictly required in EMS 3.2, but it is required for 4.0.
  33. ;
  34. ; XMS2EMS implements a number of procedures that functions may call upon
  35. ; to perform certain often-needed tasks such as verifying that a handle is
  36. ; valid or mapping a logical page to a physical page. The procedures are:
  37. ;
  38. ;   GET_FREE_PAGES      Return the number of unallocated EMS pages
  39. ;   GET_FREE_HANDLE     Return the number of the next free handle
  40. ;   ALLOCATE_PAGES      Allocate EMS memory and validate the handle
  41. ;   RELEASE_PAGES       Release all EMS pages and invalidate the handle
  42. ;   CHECK_HANDLE        Verify that the handle is valid
  43. ;   CHECK_SAVE_MAP      Search the save area for a specified entry
  44. ;   GET_PAGE_COUNT      Return the number of EMS pages assigned to a handle
  45. ;   GET_ABS_PAGE        Convert logical page number to absolute page number
  46. ;   MAP_EMS_PAGE        Map a logical (absolute) page to a physical page
  47. ;   RESTORE_PAGE_MAP    Restore a mapping context
  48. ;
  49. ; Calling conventions are documented in the procedure headers.
  50. ;****************************************************************************
  51.  
  52. KEEPBX                  equ     4
  53. KEEPCX                  equ     2
  54. KEEPDX                  equ     1
  55. KEEPNONE                equ     0
  56.  
  57. HARDWARE_ERROR          equ     81h             ;EMS error returns
  58. INVALID_HANDLE          equ     83h
  59. INVALID_FUNCTION        equ     84h
  60. NO_MORE_HANDLES         equ     85h
  61. TOO_FEW_TOTAL_PAGES     equ     87h
  62. TOO_FEW_LOGICAL_PAGES   equ     88h
  63. ZERO_PAGES_REQUESTED    equ     89h
  64. INVALID_LOGICAL_PAGE    equ     8Ah
  65. INVALID_PHYS_PAGE       equ     8Bh
  66. SAVE_AREA_FULL          equ     8Ch
  67. MAP_ALREADY_SAVED       equ     8Dh
  68. MAP_NOT_FOUND           equ     8Eh
  69. INVALID_SUBFUNCTION     equ     8Fh
  70.  
  71. code            segment
  72.                 assume  cs:code,ds:nothing
  73.                 org     00h
  74.  
  75. ;////////////////////////////////////////////////////////////////////////////
  76. ;                           Device Driver Header
  77. ;////////////////////////////////////////////////////////////////////////////
  78.  
  79. header          dd      0FFFFh                  ;Pointer to next device
  80.                 dw      8000h                   ;Device attribute word
  81.                 dw      offset strat            ;Strategy routine address
  82.                 dw      offset intr             ;Interrupt routine address
  83. devname         db      "EMMXXXX0"              ;Device name
  84.  
  85. ;////////////////////////////////////////////////////////////////////////////
  86. ;                             Strategy Routine
  87. ;////////////////////////////////////////////////////////////////////////////
  88.  
  89. rqst_header     dd      ?                       ;Request header
  90.  
  91. strat           proc    far
  92.                 mov     word ptr cs:[rqst_header],bx
  93.                 mov     word ptr cs:[rqst_header+2],es
  94.                 ret
  95. strat           endp
  96.  
  97. ;////////////////////////////////////////////////////////////////////////////
  98. ;                            Interrupt Routine
  99. ;////////////////////////////////////////////////////////////////////////////
  100.  
  101. intr            proc    far
  102.                 push    ax                      ;Save registers
  103.                 push    bx
  104.                 push    cx
  105.                 push    dx
  106.                 push    si
  107.                 push    di
  108.                 push    ds
  109.                 push    es
  110.  
  111.                 les     di,cs:[rqst_header]     ;Point ES:DI to request
  112.                 cmp     byte ptr es:[di+2],0    ;header and exit if command
  113.                 jne     intr_exit               ;code is not 0
  114.  
  115.                 call    init                    ;Initialize the driver
  116.  
  117. intr_exit:      mov     word ptr es:[di+3],100h ;"Done" code
  118.                 pop     es                      ;Restore registers and
  119.                 pop     ds                      ;return to caller
  120.                 pop     di
  121.                 pop     si
  122.                 pop     dx
  123.                 pop     cx
  124.                 pop     bx
  125.                 pop     ax
  126.                 ret
  127. intr            endp
  128.  
  129. ;****************************************************************************
  130. ;                            Device Driver Data
  131. ;****************************************************************************
  132.  
  133. ftable          dw      offset emm_function_01          ;Jump table
  134.                 dw      offset emm_function_02
  135.                 dw      offset emm_function_03
  136.                 dw      offset emm_function_04
  137.                 dw      offset emm_function_05
  138.                 dw      offset emm_function_06
  139.                 dw      offset emm_function_07
  140.                 dw      offset emm_function_08
  141.                 dw      offset emm_function_09
  142.                 dw      offset emm_function_10
  143.                 dw      offset emm_function_11
  144.                 dw      offset emm_function_12
  145.                 dw      offset emm_function_13
  146.                 dw      offset emm_function_14
  147.                 dw      offset emm_function_15
  148.  
  149. xmm             dd      ?                       ;XMS driver entry point
  150. handles         dw      64                      ;Number of EMM handles
  151. memory          dw      256                     ;Kilobytes available
  152. pages           dw      ?                       ;EMS pages available
  153. page_frame      dw      ?                       ;Page frame segment
  154. emb_handle      dw      ?                       ;EMB handle
  155. active_handles  db      1                       ;Active EMS handles
  156. hndl_table_addr dw      ?                       ;Address of handle table
  157. entry_flag      db      0                       ;0=First call to INT 67h
  158. ems_version     db      32h                     ;EMS version number
  159.  
  160. page_map_0      dw      0FFFFh                  ;Array that holds the
  161. page_map_1      dw      0FFFFh                  ;absolute page numbers
  162. page_map_2      dw      0FFFFh                  ;mapped to physical
  163. page_map_3      dw      0FFFFh                  ;pages 0 thru 3
  164.  
  165. saved_maps      db      240h dup (0FFh)         ;Page map save area
  166.  
  167. ;****************************************************************************
  168. ; INT67H handles calls to the expanded memory manager. The value passed
  169. ; back to this routine in BP by the function routines determines what reg-
  170. ; isters are popped off the stack. Bit 0 corresponds to DX; bit 1 to CX;
  171. ; and bit 2 to BX. If the bit is set, then the corresponding register is
  172. ; not restored from the stack.
  173. ;****************************************************************************
  174.  
  175.                 assume  ds:nothing
  176.  
  177. int67h          proc    far
  178.                 sti                             ;Enable interrupts
  179.                 cmp     ah,40h                  ;Return error code 84h if
  180.                 jb      invalid_code            ;function code is less
  181.                 cmp     ah,4Eh                  ;than 40h or greater
  182.                 ja      invalid_code            ;than 4Eh
  183.  
  184.                 push    bp                      ;Save registers
  185.                 push    ax
  186.                 push    bx
  187.                 push    cx
  188.                 push    dx
  189.                 push    si
  190.                 push    di
  191.                 push    ds
  192.                 push    es
  193.  
  194.                 cld                             ;Clear direction flag
  195.                 push    bx                      ;Save BX
  196.                 mov     bx,cs                   ;Point DS to this segment
  197.                 mov     ds,bx
  198.                 assume  ds:code
  199.                 mov     es,bx                   ;Point ES to this segment
  200.  
  201.                 cmp     entry_flag,0            ;Initialize the driver's
  202.                 jne     int67h_1                ;data area if this is
  203.                 mov     entry_flag,1            ;the first time INT 67h
  204.                 call    init_ems_data           ;has been called
  205.  
  206. int67h_1:       sub     ah,40h                  ;Convert function number in
  207.                 mov     bl,ah                   ;AX to offset address of
  208.                 xor     bh,bh                   ;handling routine
  209.                 shl     bx,1
  210.                 mov     ax,[offset ftable+bx]
  211.                 pop     bx                      ;Restore BX
  212.  
  213.                 call    ax                      ;Call EMM function
  214.  
  215.                 pop     es                      ;Restore registers and exit
  216.                 pop     ds
  217.                 assume  ds:nothing
  218.                 pop     di
  219.                 pop     si
  220.  
  221.                 shr     bp,1                    ;Restore DX if bit in BP
  222.                 jc      popreg1                 ;is not set
  223.                 pop     dx
  224.                 jmp     short popreg2
  225. popreg1:        add     sp,2
  226.                 
  227. popreg2:        shr     bp,1                    ;Restore CX if bit in BP
  228.                 jc      popreg3                 ;is not set
  229.                 pop     cx
  230.                 jmp     short popreg4
  231. popreg3:        add     sp,2
  232.  
  233. popreg4:        shr     bp,1                    ;Restore BX if bit in BP
  234.                 jc      popreg5                 ;is not set
  235.                 pop     bx
  236.                 jmp     short popreg6
  237. popreg5:        add     sp,2
  238.  
  239. popreg6:        add     sp,2                    ;Skip AX
  240.                 pop     bp                      ;Restore BP
  241.                 iret                            ;Return to caller
  242.  
  243. invalid_code:   mov     ah,INVALID_FUNCTION     ;Function not supported
  244.                 iret
  245. int67h          endp
  246.  
  247. ;****************************************************************************
  248. ; INIT_EMS_DATA initializes the driver's data space.
  249. ;****************************************************************************
  250.  
  251.                 assume  ds:code
  252.  
  253. init_ems_data   proc    near
  254.                 push    ax                      ;Save registers
  255.                 push    bx
  256.                 push    cx
  257.                 push    di
  258.                 push    es
  259.  
  260.                 mov     di,offset page_table    ;Initialize the page table
  261.                 mov     cx,pages                ;by filling it with FFs
  262.                 shl     cx,1
  263.                 mov     ax,0FFFFh
  264.                 rep     stosw
  265.  
  266.                 mov     di,hndl_table_addr      ;Initialize the handle table
  267.                 mov     cx,handles              ;by filling it with
  268.                 xor     al,al                   ;zeroes
  269.                 rep     stosb
  270.                 mov     di,hndl_table_addr      ;Mark handle 0 as in use
  271.                 mov     byte ptr [di],1
  272.  
  273.                 pop     es                      ;Restore registers and
  274.                 pop     di                      ;exit
  275.                 pop     cx
  276.                 pop     bx
  277.                 pop     ax
  278.                 ret
  279. init_ems_data   endp
  280.  
  281. ;****************************************************************************
  282. ; EMM Function 1 (Get Status)
  283. ;****************************************************************************
  284.  
  285.                 assume  ds:code
  286.  
  287. emm_function_01 proc    near
  288.                 xor     ah,ah                   ;Zero AH for return
  289.                 mov     bp,KEEPNONE
  290.                 ret
  291. emm_function_01 endp
  292.  
  293. ;****************************************************************************
  294. ; EMM Function 2 (Get Page Frame Segment Address)
  295. ;****************************************************************************
  296.  
  297.                 assume  ds:code
  298.  
  299. emm_function_02 proc    near
  300.                 mov     bx,page_frame           ;Place page frame address
  301.                 xor     ah,ah                   ;in BX and zero AH
  302.                 mov     bp,KEEPBX
  303.                 ret
  304. emm_function_02 endp
  305.  
  306. ;****************************************************************************
  307. ; EMM Function 3 (Get Unallocated Page Count)
  308. ;****************************************************************************
  309.  
  310.                 assume  ds:code
  311.  
  312. emm_function_03 proc    near
  313.                 call    get_free_pages          ;Free pages in BX
  314.                 mov     dx,pages                ;Total pages in DX
  315.                 xor     ah,ah                   ;Zero AH for return
  316.                 mov     bp,KEEPBX or KEEPDX
  317.                 ret
  318. emm_function_03 endp
  319.  
  320. ;****************************************************************************
  321. ; EMM Function 4 (Allocate Pages)
  322. ;****************************************************************************
  323.  
  324.                 assume  ds:code
  325.  
  326. emm_function_04 proc    near
  327.                 mov     ah,ZERO_PAGES_REQUESTED ;Error if zero pages were
  328.                 cmp     bx,0                    ;requested
  329.                 je      emm4_exit
  330.  
  331.                 mov     ah,TOO_FEW_TOTAL_PAGES  ;Error if request exceeds
  332.                 cmp     bx,pages                ;count of total pages
  333.                 ja      emm4_exit
  334.  
  335.                 mov     dx,bx                           ;Transfer count
  336.                 call    get_free_pages                  ;Error if request
  337.                 mov     ah,TOO_FEW_LOGICAL_PAGES        ;exceeds count of
  338.                 cmp     dx,bx                           ;pages free
  339.                 ja      emm4_exit
  340.  
  341.                 push    dx                      ;Save page count
  342.                 call    get_free_handle         ;Get first free handle
  343.                 pop     cx                      ;Retrieve page count
  344.                 mov     ah,NO_MORE_HANDLES      ;Error if no handles are
  345.                 jc      emm4_exit               ;currently available
  346.  
  347.                 call    allocate_pages          ;Allocate the EMS pages
  348.                 xor     ah,ah                   ;Zero AH for return
  349. emm4_exit:      mov     bp,KEEPDX
  350.                 ret
  351. emm_function_04 endp
  352.  
  353. ;****************************************************************************
  354. ; EMM Function 5 (Map/Unmap Handle Page)
  355. ;
  356. ; Note: Logic was added in version 1.1 so that a logical page number
  357. ; equal to FFFFh unmaps the corresponding physical page.
  358. ;****************************************************************************
  359.  
  360.                 assume  ds:code
  361.  
  362. PHYSICAL_PAGE   equ     byte ptr [bp+18]
  363. LOGICAL_PAGE    equ     word ptr [bp]
  364.  
  365. emm_function_05 proc    near
  366.                 push    bx                      ;Save logical page number
  367.                 mov     bp,sp                   ;Make values addressable
  368.  
  369.                 call    check_handle            ;Error if handle is not
  370.                 mov     ah,INVALID_HANDLE       ;valid
  371.                 jc      emm5_exit
  372.  
  373.                 mov     ah,INVALID_PHYS_PAGE    ;Error if physical page
  374.                 cmp     PHYSICAL_PAGE,3         ;number is greater
  375.                 ja      emm5_exit               ;than 3
  376.  
  377.                 mov     bx,0FFFFh               ;Set absolute page to FFFFh
  378.                 cmp     LOGICAL_PAGE,0FFFFh     ;Branch if the logical page
  379.                 je      emm05_1                 ;number is FFFFh
  380.  
  381.                 call    get_page_count          ;Get handle's page count
  382.                 mov     ah,INVALID_LOGICAL_PAGE ;Error if logical page
  383.                 cmp     LOGICAL_PAGE,bx         ;number is out of
  384.                 jae     emm5_exit               ;range
  385.  
  386.                 mov     bx,LOGICAL_PAGE         ;Compute the absolute page
  387.                 call    get_abs_page            ;number
  388.                 mov     bx,ax                   ;Transfer result to BX
  389. emm05_1:        mov     al,PHYSICAL_PAGE        ;Physical page number in AL
  390.                 call    map_ems_page            ;Map the page
  391.                 mov     ah,HARDWARE_ERROR       ;Exit on error
  392.                 jc      emm5_exit
  393.                 xor     ah,ah                   ;Zero AH for return
  394.  
  395. emm5_exit:      mov     bp,KEEPNONE             ;Set BP
  396.                 add     sp,2                    ;Clear the stack
  397.                 ret
  398. emm_function_05 endp
  399.  
  400. ;****************************************************************************
  401. ; EMM Function 6 (Deallocate Pages)
  402. ;****************************************************************************
  403.  
  404.                 assume  ds:code
  405.  
  406. emm_function_06 proc    near
  407.                 call    check_handle            ;Error if DX contains an
  408.                 mov     ah,INVALID_HANDLE       ;invalid handle
  409.                 jc      emm6_exit
  410.                 call    release_pages           ;Deallocate the pages
  411.                 xor     ah,ah                   ;Zero AH for return
  412. emm6_exit:      mov     bp,KEEPNONE
  413.                 ret
  414. emm_function_06 endp
  415.  
  416. ;****************************************************************************
  417. ; EMM Function 7 (Get Version)
  418. ;****************************************************************************
  419.  
  420.                 assume  ds:code
  421.  
  422. emm_function_07 proc    near
  423.                 mov     al,ems_version          ;Load version number in AL
  424.                 xor     ah,ah                   ;Zero AH for return
  425.                 mov     bp,KEEPNONE
  426.                 ret
  427. emm_function_07 endp
  428.  
  429. ;****************************************************************************
  430. ; EMM Function 8 (Save Page Map)
  431. ;****************************************************************************
  432.  
  433.                 assume  ds:code
  434.  
  435. emm_function_08 proc    near
  436.                 call    check_handle            ;Error if DX contains an
  437.                 mov     ah,INVALID_HANDLE       ;invalid handle
  438.                 jc      emm8_exit
  439.  
  440.                 call    check_save_map          ;Error if save area already
  441.                 mov     ah,MAP_ALREADY_SAVED    ;contains a map for this
  442.                 jnc     emm8_exit               ;handle
  443.  
  444.                 push    dx                      ;Save handle
  445.                 mov     dx,0FFh                 ;Find address of first free
  446.                 call    check_save_map          ;map in the save area
  447.                 pop     dx                      ;Retrieve handle
  448.                 mov     ah,SAVE_AREA_FULL       ;Error if the save area
  449.                 jc      emm8_exit               ;is full
  450.  
  451.                 mov     di,si                   ;Store the handle number
  452.                 mov     [di],dl
  453.                 inc     di
  454.                 mov     si,offset page_map_0    ;Copy maps for pages 0
  455.                 mov     cx,4                    ;thru 3 to the save
  456.                 rep     movsw                   ;area
  457.                 xor     ah,ah                   ;Zero AH for return
  458. emm8_exit:      mov     bp,KEEPNONE
  459.                 ret
  460. emm_function_08 endp
  461.  
  462. ;****************************************************************************
  463. ; EMM Function 9 (Restore Page Map)
  464. ;****************************************************************************
  465.  
  466.                 assume  ds:code
  467.  
  468. emm_function_09 proc    near
  469.                 call    check_handle            ;Error if DX contains an
  470.                 mov     ah,INVALID_HANDLE       ;invalid handle
  471.                 jc      emm9_exit
  472.  
  473.                 call    check_save_map          ;Error if no map exists
  474.                 mov     ah,MAP_NOT_FOUND        ;for this handle
  475.                 jc      emm9_exit
  476.  
  477.                 mov     byte ptr [si],0FFh      ;Mark map as unused
  478.                 inc     si                      ;Advance SI to saved map
  479.                 call    restore_page_map        ;Restore the page map
  480.                 mov     ah,HARDWARE_ERROR       ;Exit on error
  481.                 jc      emm9_exit
  482.                 xor     ah,ah                   ;Zero AH for return
  483. emm9_exit:      mov     bp,KEEPNONE
  484.                 ret
  485. emm_function_09 endp
  486.  
  487. ;****************************************************************************
  488. ; EMM Function 10 (Reserved)
  489. ;****************************************************************************
  490.  
  491.                 assume  ds:code
  492.  
  493. emm_function_10 proc    near
  494.                 mov     ah,INVALID_FUNCTION
  495.                 mov     bp,KEEPNONE
  496.                 ret
  497. emm_function_10 endp
  498.  
  499. ;****************************************************************************
  500. ; EMM Function 11 (Reserved)
  501. ;****************************************************************************
  502.  
  503.                 assume  ds:code
  504.  
  505. emm_function_11 proc    near
  506.                 mov     ah,INVALID_FUNCTION
  507.                 mov     bp,KEEPNONE
  508.                 ret
  509. emm_function_11 endp
  510.  
  511. ;****************************************************************************
  512. ; EMM Function 12 (Get Handle Count)
  513. ;****************************************************************************
  514.  
  515.                 assume  ds:code
  516.  
  517. emm_function_12 proc    near
  518.                 mov     bl,active_handles       ;Place count in BL
  519.                 xor     bh,bh                   ;Byte to word in BX
  520.                 xor     ah,ah                   ;Zero AH for return
  521. emm12_exit:     mov     bp,KEEPBX
  522.                 ret
  523. emm_function_12 endp
  524.  
  525. ;****************************************************************************
  526. ; EMM Function 13 (Get Handle Pages)
  527. ;****************************************************************************
  528.  
  529.                 assume  ds:code
  530.  
  531. emm_function_13 proc    near
  532.                 xor     bx,bx                   ;Exit with count equal to
  533.                 or      dx,dx                   ;0 if handle number is 0
  534.                 jz      emm13_1
  535.                 call    check_handle            ;Error if DX contains an
  536.                 mov     ah,INVALID_HANDLE       ;invalid handle
  537.                 jc      emm13_exit
  538.                 call    get_page_count          ;Get page count in BX
  539. emm13_1:        xor     ah,ah                   ;Zero AH for return
  540. emm13_exit:     mov     bp,KEEPBX
  541.                 ret
  542. emm_function_13 endp
  543.  
  544. ;****************************************************************************
  545. ; EMM Function 14 (Get All Handle Pages)
  546. ;****************************************************************************
  547.  
  548.                 assume  ds:code
  549.  
  550. emm_function_14 proc    near
  551.                 mov     bp,sp                   ;Restore value of ES on
  552.                 mov     es,[bp+2]               ;entry to this function
  553.                 mov     ax,cs                   ;Point ES back to this
  554.                 mov     es,ax                   ;segment
  555.                 mov     dx,-1                   ;Initialize handle number
  556.                 mov     cl,active_handles       ;Initialize handle count
  557.                 xor     ch,ch                   ;Byte to word in CX
  558.  
  559. emm14_1:        inc     dx                      ;Increment handle
  560.                 push    cx                      ;Save count
  561.                 push    di                      ;Save DI
  562.                 call    check_handle            ;See if handle in DX is valid
  563.                 pop     di                      ;Retrieve DI
  564.                 pop     cx                      ;Retrieve count
  565.                 jc      emm14_1                 ;Branch if handle invalid
  566.  
  567.                 push    cx                      ;Save count again
  568.                 call    get_page_count          ;Get page count if valid
  569.                 mov     es,[bp+2]               ;Point ES to user data space
  570.                 mov     es:[di],dx              ;Store handle number
  571.                 mov     es:[di+2],bx            ;Store page count
  572.                 add     di,4                    ;Advance DI
  573.                 mov     ax,cs                   ;Point ES back to this
  574.                 mov     es,ax                   ;segment
  575.                 pop     cx                      ;Retrieve count
  576.                 loop    emm14_1                 ;Loop until done
  577.  
  578. emm14_exit:     jmp     emm_function_12         ;Exit through function 12
  579. emm_function_14 endp
  580.  
  581. ;****************************************************************************
  582. ; EMM Function 15 (Get/Set Page Map)
  583. ;****************************************************************************
  584.  
  585.                 assume  ds:code
  586.  
  587. emm_function_15 proc    near
  588.                 mov     bp,sp                   ;Make stack addressable
  589.                 mov     al,byte ptr [bp+16]     ;Retrieve subfunction code
  590.                 mov     ah,INVALID_SUBFUNCTION  ;Branch if subfunction code
  591.                 cmp     al,0                    ;is other than 0
  592.                 jne     emm15_1
  593.                 mov     bp,sp                   ;Restore value of ES on
  594.                 mov     es,[bp+2]               ;entry to this function
  595.                 mov     si,offset page_map_0    ;Copy maps for pages 0
  596.                 mov     cx,4                    ;thru 3 to the user's
  597.                 rep     movsw                   ;data space
  598.                 xor     ah,ah                   ;Zero AH for return
  599.                 jmp     short emm15_exit        ;Exit
  600. ;
  601. ; Function 15, Subfunction 1.
  602. ;
  603. emm15_1:        cmp     al,1                    ;Branch if subfunction code
  604.                 jne     emm15_2                 ;is other than 1
  605.                 mov     bp,sp                   ;Restore value of DS on
  606. emm15_1_1:      mov     ds,[bp+4]               ;entry to this function
  607.                 assume  ds:nothing
  608.                 call    restore_page_map        ;Restore the page map
  609.                 mov     ah,HARDWARE_ERROR       ;Exit on error
  610.                 jc      emm15_exit
  611.                 xor     ah,ah                   ;Zero AH for return
  612.                 jmp     short emm15_exit        ;Exit
  613.                 assume  ds:code
  614. ;
  615. ; Function 15, Subfunction 2.
  616. ;
  617. emm15_2:        cmp     al,2                    ;Branch if subfunction code
  618.                 jne     emm15_3                 ;is other than 2
  619.                 mov     bp,sp                   ;Restore value of ES on
  620.                 mov     es,[bp+2]               ;entry to this function
  621.                 push    si                      ;Save SI
  622.                 mov     si,offset page_map_0    ;Copy maps for pages 0
  623.                 mov     cx,4                    ;thru 3 to the user's
  624.                 rep     movsw                   ;data space
  625.                 pop     si                      ;Restore SI
  626.                 jmp     emm15_1_1               ;Branch and finish
  627. ;
  628. ; Function 15, Subfunction 3.
  629. ;
  630. emm15_3:        cmp     al,3                    ;Error if subfunction number
  631.                 jne     emm15_exit              ;is other than 3
  632.                 mov     ax,0008h                ;Prepare AX for return
  633. emm15_exit:     mov     bp,KEEPNONE
  634.                 ret
  635. emm_function_15 endp
  636.  
  637. ;****************************************************************************
  638. ; GET_FREE_PAGES returns the number of unallocated pages in BX. On entry,
  639. ; DS must point to the code segment.
  640. ;****************************************************************************
  641.  
  642.                 assume  ds:code
  643.  
  644. get_free_pages  proc    near
  645.                 mov     si,offset page_table    ;Point SI to page table
  646.                 mov     cx,pages                ;Set CX to number of pages
  647.                 xor     bx,bx                   ;Zero unallocated page count
  648. getfree1:       lodsw                           ;Get page table entry
  649.                 cmp     ax,0FFFFh               ;Branch if allocated
  650.                 jne     getfree2
  651.                 inc     bx                      ;Increment count
  652. getfree2:       add     si,2                    ;Skip next field in table
  653.                 loop    getfree1                ;Loop until done
  654.                 ret
  655. get_free_pages  endp
  656.  
  657. ;****************************************************************************
  658. ; GET_FREE_HANDLE returns the number of the lowest available handle in DX.
  659. ; On return, carry set means no handles are available. On entry, ES must
  660. ; point to the code segment.
  661. ;****************************************************************************
  662.  
  663.                 assume  ds:code
  664.  
  665. get_free_handle proc    near
  666.                 mov     cx,handles              ;Place count in CX
  667.                 mov     al,00h                  ;Search the handle table
  668.                 mov     di,hndl_table_addr      ;until an unallocated
  669.                 repne   scasb                   ;handle is found
  670.                 je      gethand1                ;Branch if handle found
  671.                 stc                             ;Set carry and return
  672.                 ret
  673. gethand1:       inc     cx                      ;Compute handle number
  674.                 mov     dx,handles              ;in DX
  675.                 sub     dx,cx
  676.                 clc                             ;Clear carry and return
  677.                 ret
  678. get_free_handle endp
  679.  
  680. ;****************************************************************************
  681. ; ALLOCATE_PAGES allocates the number of EMS pages in CX to the handle in
  682. ; DX and validates the handle. No checking is performed to make sure the
  683. ; number of pages requested in CX are available. On entry, DS must point
  684. ; to the code segment.
  685. ;****************************************************************************
  686.  
  687.                 assume  ds:code
  688.  
  689. allocate_pages  proc    near
  690.                 inc     active_handles          ;Increment handle count
  691.                 mov     si,hndl_table_addr      ;Validate the handle
  692.                 add     si,dx
  693.                 mov     byte ptr [si],1
  694.                 jcxz    allocpage2              ;Branch if CX=0
  695.                 mov     bx,0                    ;Initialize log page number
  696.                 mov     si,offset page_table    ;Point SI to page table
  697. allocpage1:     lodsw                           ;Get an entry
  698.                 add     si,2                    ;Skip logical page number
  699.                 cmp     ax,0FFFFh               ;Branch if the page is
  700.                 jne     allocpage1              ;already allocated
  701.                 mov     [si-4],dx               ;Write handle to table
  702.                 mov     [si-2],bx               ;Write logical page number
  703.                 inc     bx                      ;Increment page number
  704.                 loop    allocpage1              ;Loop until done
  705. allocpage2:     ret
  706. allocate_pages  endp
  707.  
  708. ;****************************************************************************
  709. ; RELEASE_PAGES deallocates all pages that belong to the handle in DX and
  710. ; invalidates the handle. On entry, both DS and ES must point to the code
  711. ; segment.
  712. ;****************************************************************************
  713.  
  714.                 assume  ds:code
  715.  
  716. release_pages   proc    near
  717.                 cmp     dx,0                    ;Branch if handle number
  718.                 je      relpage0                ;is 0
  719.  
  720.                 dec     active_handles          ;Decrement handle count
  721.                 mov     si,hndl_table_addr      ;Invalidate the handle
  722.                 add     si,dx
  723.                 mov     byte ptr [si],0
  724.  
  725. relpage0:       mov     si,offset page_table    ;Point SI to page table
  726.                 mov     cx,pages                ;Initialize page count
  727. relpage1:       lodsw                           ;Get a page table entry
  728.                 cmp     ax,dx                   ;Branch if the page belongs
  729.                 jne     relpage2                ;to another handle
  730.                 mov     word ptr [si-2],0FFFFh  ;Mark the page as unused
  731.                 mov     word ptr [si],0000h     ;Zero the logical page number
  732. relpage2:       add     si,2                    ;Skip logical page number
  733.                 loop    relpage1                ;Loop until done
  734.                 ret
  735. release_pages   endp
  736.  
  737. ;****************************************************************************
  738. ; CHECK_HANDLE returns with carry clear if the handle in DX is a valid
  739. ; handle, carry set if DX does not contain a valid handle. On entry, DS
  740. ; must point to the code segment.
  741. ;****************************************************************************
  742.  
  743.                 assume  ds:code
  744.  
  745. check_handle    proc    near
  746.                 cmp     dx,handles              ;Handle invalid if number is
  747.                 jae     handle_bad              ;greater than handle count
  748.                 mov     si,hndl_table_addr      ;Handle invalid if corre-
  749.                 add     si,dx                   ;sponding byte in handle
  750.                 cmp     byte ptr [si],0         ;table is 0
  751.                 je      handle_bad
  752.                 clc                             ;Clear carry and return
  753.                 ret
  754. handle_bad:     stc                             ;Set carry and return
  755.                 ret
  756. check_handle    endp
  757.  
  758. ;****************************************************************************
  759. ; CHECK_SAVE_MAP returns with carry clear if the page map save area
  760. ; contains a page map for the handle in DX, carry set if it does not.
  761. ; If a handle is found, the offset address of the corresponding page
  762. ; map is returned in SI. To search for a free map in the save area,
  763. ; call this procedure with DX set to 0FFh. On entry, DS must point
  764. ; to the code segment.
  765. ;****************************************************************************
  766.  
  767.                 assume  ds:code
  768.  
  769. check_save_map  proc    near
  770.                 mov     si,offset saved_maps    ;Point SI to save area
  771.                 mov     cx,64                   ;Initialize count in CX
  772. csm1:           cmp     byte ptr [si],dl        ;Check one entry
  773.                 je      map_found               ;Branch if handle matches
  774.                 add     si,9                    ;Point SI to next entry
  775.                 loop    csm1                    ;Loop until done
  776.                 stc                             ;Set carry and return
  777.                 ret
  778. map_found:      clc                             ;Clear carry and return
  779.                 ret
  780. check_save_map  endp
  781.  
  782. ;****************************************************************************
  783. ; GET_PAGE_COUNT returns in BX the number of logical pages allocated to
  784. ; the handle in DX. No checking is performed to make sure the handle is
  785. ; valid. On entry, DS must point to the code segment.
  786. ;****************************************************************************
  787.  
  788.                 assume  ds:code
  789.  
  790. get_page_count  proc    near
  791.                 mov     si,offset page_table    ;Point SI to page table
  792.                 mov     cx,pages                ;Initialize count in CX
  793.                 xor     bx,bx                   ;Initalize page count
  794. gpc1:           lodsw                           ;Get a page table entry
  795.                 cmp     ax,dx                   ;Increment page count if
  796.                 jne     gpc2                    ;the handles match
  797.                 inc     bx
  798. gpc2:           add     si,2                    ;Skip logical page number
  799.                 loop    gpc1                    ;Loop until done
  800.                 ret
  801. get_page_count  endp
  802.  
  803. ;****************************************************************************
  804. ; GET_ABS_PAGE returns in AX the absolute page number that corresponds to
  805. ; the handle in DX and the logical page number in BX. No checking is per-
  806. ; formed to make sure the handle and the logical page number are valid.
  807. ; On entry, DS must point to the code segment.
  808. ;****************************************************************************
  809.  
  810.                 assume  ds:code
  811.  
  812. get_abs_page    proc    near
  813.                 mov     si,offset page_table    ;Point SI to page table
  814.                 mov     cx,pages                ;Initialize page count
  815. gpa1:           lodsw                           ;Get a page table entry
  816.                 cmp     ax,dx                   ;Branch if page does not
  817.                 jne     gpa2                    ;belong to handle in DX
  818.                 cmp     bx,[si]                 ;Branch if logical page
  819.                 je      gpa3                    ;numbers match
  820. gpa2:           add     si,2                    ;Skip logical page number
  821.                 loop    gpa1                    ;Loop back for more
  822. gpa3:           mov     ax,pages                ;Compute absolute page
  823.                 sub     ax,cx                   ;number in AX
  824.                 ret
  825. get_abs_page    endp
  826.  
  827. ;****************************************************************************
  828. ; MAP_EMS_PAGE maps the absolute page whose number is passed in BX
  829. ; to the physical page whose number is passed in AL. On return, carry
  830. ; clear means the page was mapped. Carry set means an error occurred.
  831. ; On entry, DS must point to the code segment.
  832. ;****************************************************************************
  833.  
  834. EMS_PPAGE       equ     byte ptr [bp+2]
  835. EMS_APAGE       equ     word ptr [bp]
  836.  
  837.                 assume  ds:code
  838.  
  839. map_ems_page    proc    near
  840.                 push    bp                      ;Save BP
  841.                 push    ax                      ;Save page numbers on the
  842.                 push    bx                      ;stack
  843.                 mov     bp,sp                   ;Make stack addressable
  844.  
  845.                 mov     si,offset page_map_0    ;Compute offset into page
  846.                 xor     ah,ah                   ;map array for specified
  847.                 shl     ax,1                    ;physical page
  848.                 add     si,ax
  849.                 mov     ax,[si]                 ;Get absolute page number
  850.                 cmp     ax,0FFFFh               ;Branch if the page is
  851.                 je      mep1                    ;currently unmapped
  852.  
  853.                 mov     bl,EMS_PPAGE            ;Get physical page number
  854.                 call    copy_p2a                ;Copy page to XMS memory
  855.                 jc      mep_error               ;Exit on error
  856.  
  857. mep1:           mov     ax,EMS_APAGE            ;Get absolute page number
  858.                 cmp     ax,0FFFFh               ;Branch if page number is
  859.                 je      mep2                    ;FFFFh
  860.                 mov     bl,EMS_PPAGE            ;Get physical page number
  861.                 call    copy_a2p                ;Copy page from XMS memory
  862.                 jc      mep_error               ;Exit on error
  863.  
  864. mep2:           mov     si,offset page_map_0    ;Compute offset into page
  865.                 mov     al,EMS_PPAGE            ;map array for specified
  866.                 xor     ah,ah                   ;physical page
  867.                 shl     ax,1
  868.                 add     si,ax
  869.                 mov     bx,EMS_APAGE            ;Get absolute page number
  870.                 mov     word ptr [si],bx        ;Store absolute page number
  871.  
  872.                 add     sp,4                    ;Clear the stack
  873.                 pop     bp                      ;Restore BP
  874.                 clc                             ;Clear carry
  875.                 ret                             ;Return
  876.  
  877. mep_error:      add     sp,4                    ;Clear the stack
  878.                 pop     bp                      ;Restore BP
  879.                 stc                             ;Set carry
  880.                 ret                             ;Return
  881. map_ems_page    endp
  882.  
  883. ;****************************************************************************
  884. ; COPY_P2A copies the physical page whose page number is passed in BL to the
  885. ; page in XMS memory whose absolute page number is passed in AX. On return,
  886. ; carry set means the operation succeeded, carry set means it did not. On
  887. ; entry, DS must point to the code segment.
  888. ;****************************************************************************
  889.  
  890. XMS_LENGTH_LO           equ     word ptr [bp]
  891. XMS_LENGTH_HI           equ     word ptr [bp+2]
  892. XMS_SRC_HANDLE          equ     word ptr [bp+4]
  893. XMS_SRC_OFFSET_LO       equ     word ptr [bp+6]
  894. XMS_SRC_OFFSET_HI       equ     word ptr [bp+8]
  895. XMS_DST_HANDLE          equ     word ptr [bp+10]
  896. XMS_DST_OFFSET_LO       equ     word ptr [bp+12]
  897. XMS_DST_OFFSET_HI       equ     word ptr [bp+14]
  898.  
  899.                 assume  ds:code
  900.  
  901. copy_p2a        proc    near
  902.                 push    bp                      ;Save BP
  903.                 sub     sp,16                   ;Make room on stack
  904.                 mov     bp,sp                   ;Make stack addressable
  905.  
  906.                 mov     XMS_LENGTH_LO,16384     ;Set block length (16K)
  907.                 mov     XMS_LENGTH_HI,0
  908.  
  909.                 mov     dx,emb_handle           ;Set destination handle
  910.                 mov     XMS_DST_HANDLE,dx
  911.  
  912.                 xor     dx,dx                   ;Compute offset into EMB
  913.                 mov     cx,14                   ;that corresponds to the
  914. cp2a_1:         shl     ax,1                    ;absolute page number in
  915.                 rcl     dx,1                    ;AX
  916.                 loop    cp2a_1
  917.                 mov     XMS_DST_OFFSET_LO,ax    ;Write result to XMS
  918.                 mov     XMS_DST_OFFSET_HI,dx    ;parameter block
  919.  
  920.                 mov     XMS_SRC_HANDLE,0        ;Set source handle
  921.  
  922.                 mov     ax,16384                ;Compute offset into page
  923.                 xor     bh,bh                   ;frame that corresponds to
  924.                 mul     bx                      ;the physical page number
  925.                 mov     XMS_SRC_OFFSET_LO,ax    ;Write result to XMS
  926.                 mov     ax,page_frame           ;parameter block
  927.                 mov     XMS_SRC_OFFSET_HI,ax
  928.  
  929.                 push    ds                      ;Save DS
  930.                 mov     si,bp                   ;Point DS:SI to XMS
  931.                 mov     ax,ss                   ;parameter block
  932.                 mov     ds,ax
  933.                 assume  ds:nothing
  934.                 mov     ah,0Bh                  ;XMS function code in AH
  935.                 call    cs:[xmm]                ;Execute block move
  936.                 pop     ds                      ;Retrieve DS
  937.                 assume  ds:code
  938.                 or      ax,ax                   ;Branch on error
  939.                 jz      cp2a_error
  940.  
  941.                 add     sp,16                   ;Clear the stack
  942.                 pop     bp                      ;Restore BP
  943.                 clc                             ;Clear carry
  944.                 ret                             ;Return
  945.  
  946. cp2a_error:     add     sp,16                   ;Clear the stack
  947.                 pop     bp                      ;Restore BP
  948.                 stc                             ;Set carry
  949.                 ret                             ;Return
  950. copy_p2a        endp
  951.  
  952. ;****************************************************************************
  953. ; COPY_A2P copies the page in XMS memory whose page number is passed in
  954. ; AX to the physical page whose page number is passed in BL. On return,
  955. ; carry set means the operation succeeded, carry set means it did not.
  956. ; On entry, DS must point to the code segment.
  957. ;****************************************************************************
  958.  
  959.                 assume  ds:code
  960.  
  961. copy_a2p        proc    near
  962.                 push    bp                      ;Save BP
  963.                 sub     sp,16                   ;Make room on stack
  964.                 mov     bp,sp                   ;Make stack addressable
  965.  
  966.                 mov     XMS_LENGTH_LO,16384     ;Set block length (16K)
  967.                 mov     XMS_LENGTH_HI,0
  968.  
  969.                 mov     dx,emb_handle           ;Set source handle
  970.                 mov     XMS_SRC_HANDLE,dx
  971.  
  972.                 xor     dx,dx                   ;Compute offset into EMB
  973.                 mov     cx,14                   ;that corresponds to the
  974. ca2p_1:         shl     ax,1                    ;absolute page number in
  975.                 rcl     dx,1                    ;AX
  976.                 loop    ca2p_1
  977.                 mov     XMS_SRC_OFFSET_LO,ax    ;Write result to XMS
  978.                 mov     XMS_SRC_OFFSET_HI,dx    ;parameter block
  979.  
  980.                 mov     XMS_DST_HANDLE,0        ;Set destination handle
  981.  
  982.                 mov     ax,16384                ;Compute offset into page
  983.                 xor     bh,bh                   ;frame that corresponds to
  984.                 mul     bx                      ;the physical page number
  985.                 mov     XMS_DST_OFFSET_LO,ax    ;Write result to XMS
  986.                 mov     ax,page_frame           ;parameter block
  987.                 mov     XMS_DST_OFFSET_HI,ax
  988.  
  989.                 push    ds                      ;Save DS
  990.                 mov     si,bp                   ;Point DS:SI to XMS
  991.                 mov     ax,ss                   ;parameter block
  992.                 mov     ds,ax
  993.                 assume  ds:nothing
  994.                 mov     ah,0Bh                  ;XMS function code in AH
  995.                 call    cs:[xmm]                ;Execute block move
  996.                 pop     ds                      ;Retrieve DS
  997.                 assume  ds:code
  998.                 or      ax,ax                   ;Branch on error
  999.                 jz      ca2p_error
  1000.  
  1001.                 add     sp,16                   ;Clear the stack
  1002.                 pop     bp                      ;Restore BP
  1003.                 clc                             ;Clear carry
  1004.                 ret                             ;Return
  1005.  
  1006. ca2p_error:     add     sp,16                   ;Clear the stack
  1007.                 pop     bp                      ;Restore BP
  1008.                 stc                             ;Set carry
  1009.                 ret                             ;Return
  1010. copy_a2p        endp
  1011.  
  1012. ;****************************************************************************
  1013. ; RESTORE_PAGE_MAP restores the page map whose address is passed in DS:SI.
  1014. ; On return, carry clear means the mapping succeeded. Carry set means an
  1015. ; error occurred.
  1016. ;****************************************************************************
  1017.  
  1018.                 assume  ds:nothing
  1019.  
  1020. restore_page_map proc   near
  1021.                 mov     cx,4                    ;Initialize page count
  1022. rpm_loop:       lodsw                           ;Get absolute page number
  1023.                 push    cx                      ;Save registers
  1024.                 push    si
  1025.                 push    ds
  1026.                 mov     bx,cs                   ;Point DS back to this
  1027.                 mov     ds,bx                   ;segment for now
  1028.                 mov     bx,ax                   ;Transfer it to BX
  1029.                 mov     ax,4                    ;Compute physical page
  1030.                 sub     ax,cx                   ;number in AX
  1031.                 call    map_ems_page            ;Map the EMS page
  1032.                 pop     ds                      ;Restore registers
  1033.                 pop     si
  1034.                 pop     cx
  1035.                 jc      rpm_exit                ;Exit on error
  1036.                 loop    rpm_loop                ;Loop until done
  1037.                 clc                             ;Clear carry for exit
  1038. rpm_exit:       ret
  1039. restore_page_map endp
  1040.  
  1041. ;****************************************************************************
  1042. ; INIT parses the DEVICE= line and initializes the device driver.
  1043. ;****************************************************************************
  1044.  
  1045. page_table      label   byte
  1046.  
  1047. copyright       db      "XMS2EMS 1.1 Copyright (c) 1993 Jeff Prosise",13,10
  1048.                 db      "From: PC Magazine DOS 6 Memory Management with "
  1049.                 db      "Utilities",13,10,"$"
  1050.  
  1051. errmsg0         db      "ERROR: $"
  1052. errmsg1         db      "An expanded memory manager is already installed"
  1053.                 db      13,10,"$"
  1054. errmsg2         db      "HIMEM.SYS must be installed before XMS2EMS.SYS"
  1055.                 db      13,10,"$"
  1056. errmsg3         db      "Invalid parameter or parameter out of range"
  1057.                 db      13,10,"$"
  1058. errmsg4         db      "XMS2EMS not installed"
  1059.                 db      13,10,"$"
  1060. errmsg5         db      "Insufficient XMS memory available",13,10,"$"
  1061.  
  1062. msg1            db      "Expanded memory available: $"
  1063. msg2            db      "K",13,10,"$"
  1064.  
  1065.                 assume  cs:code,ds:nothing
  1066.  
  1067. init            proc    near
  1068.                 mov     ax,cs                   ;Point DS to code segment
  1069.                 mov     ds,ax
  1070.                 mov     ah,09h                  ;Display installation
  1071.                 mov     dx,offset copyright     ;message
  1072.                 int     21h
  1073.  
  1074.                 push    di                      ;Make sure there's not
  1075.                 push    es                      ;an EMM already loaded
  1076.                 xor     ax,ax
  1077.                 mov     ds,ax
  1078.                 mov     es,ds:[19Eh]
  1079.                 mov     ax,cs
  1080.                 mov     ds,ax
  1081.                 assume  ds:code
  1082.                 mov     si,offset devname
  1083.                 mov     di,10
  1084.                 mov     cx,8
  1085.                 repe    cmpsb
  1086.                 pop     es
  1087.                 pop     di
  1088.                 jne     init2
  1089. ;
  1090. ; Display error message, zero the break address, and return.
  1091. ;
  1092.                 mov     dx,offset errmsg1
  1093. init_error:     mov     ax,cs                   ;Point DS to code segment
  1094.                 mov     ds,ax
  1095.                 push    dx                      ;Save message pointer
  1096.                 mov     ah,09h                  ;Print "ERROR:"
  1097.                 mov     dx,offset errmsg0
  1098.                 int     21h
  1099.                 pop     dx                      ;Retrieve message pointer
  1100.                 mov     ah,09h                  ;Print error message
  1101.                 int     21h
  1102.                 mov     ah,09h                  ;Print "XMS2EMS not
  1103.                 mov     dx,offset errmsg4       ;installed"
  1104.                 int     21h
  1105.                 mov     word ptr es:[di+14],0   ;Zero the break address
  1106.                 mov     word ptr es:[di+16],cs
  1107.                 ret
  1108. ;
  1109. ; Make sure HIMEM.SYS is loaded and get the driver's entry point.
  1110. ;
  1111. init2:          mov     ax,4300h                ;Make sure the driver is
  1112.                 int     2Fh                     ;present with function
  1113.                 mov     dx,offset errmsg2       ;4300h
  1114.                 cmp     al,80h
  1115.                 jne     init_error
  1116.  
  1117.                 push    es                      ;Get its entry point address
  1118.                 mov     ax,4310h                ;with function 4310h
  1119.                 int     2Fh
  1120.                 mov     word ptr xmm,bx
  1121.                 mov     word ptr xmm[2],es
  1122.                 pop     es
  1123. ;
  1124. ; Parse the DEVICE= line for parameters.
  1125. ;
  1126.                 lds     si,es:[di+18]           ;Point DS:SI to the DEVICE=
  1127.                 assume  ds:nothing              ;line
  1128.                 cld                             ;Clear direction flag
  1129.  
  1130.                 call    finddelim               ;Skip device driver name
  1131.                 jc      init5                   ;Branch if end of line
  1132.  
  1133. init3:          call    findchar                ;Find the first character
  1134.                 jc      init5                   ;Branch if end of line
  1135.  
  1136.                 cmp     byte ptr [si],"/"       ;Branch if the character is
  1137.                 jne     init4                   ;not a "/"
  1138.                 inc     si                      ;Advance past the "/"
  1139.                 lodsw                           ;Get the next two characters
  1140.                 and     al,0DFh                 ;Capitalize the first one
  1141.                 mov     dx,offset errmsg3       ;Initialize error pointer
  1142.                 cmp     ax,3D48h                ;Error if not "H="
  1143.                 jne     init_error
  1144.                 call    asc2bin                 ;Get the number following
  1145.                 mov     dx,offset errmsg3       ;the equal sign
  1146.                 jc      init_error
  1147.                 cmp     ax,8                    ;Check the range
  1148.                 jb      init_error
  1149.                 cmp     ax,255
  1150.                 ja      init_error
  1151.                 mov     cs:[handles],ax         ;Store number of handles
  1152.                 jmp     init3                   ;Return to parsing loop
  1153.  
  1154. init4:          call    asc2bin                 ;Get the number of kilobytes
  1155.                 mov     dx,offset errmsg3       ;requested
  1156.                 jc      init_error2
  1157.                 cmp     ax,256                  ;Check the range
  1158.                 jb      init_error2
  1159.                 cmp     ax,8192
  1160.                 ja      init_error2
  1161.                 mov     cs:[memory],ax          ;Store kilobytes requested
  1162.                 jmp     init3                   ;Return to parsing loop
  1163. ;
  1164. ; Allocate an extended memory block (EMB) from the XMS driver.
  1165. ;
  1166. init5:          mov     ax,cs                   ;Point DS back to the
  1167.                 mov     ds,ax                   ;code segment
  1168.                 assume  ds:code
  1169.  
  1170.                 add     memory,15               ;Round MEMORY value up to
  1171.                 and     memory,0FFF0h           ;the nearest 16K boundary
  1172.  
  1173. get_emb:        mov     ah,09h                  ;Request an EMB of the
  1174.                 mov     dx,memory               ;same length
  1175.                 call    xmm
  1176.                 or      ax,ax                   ;Branch if no error
  1177.                 jnz     init7
  1178.  
  1179. check_emb:      mov     ah,08h                  ;Get the size of the largest
  1180.                 call    xmm                     ;free EMB
  1181.                 mov     dx,offset errmsg5       ;Error if it's smaller than
  1182.                 cmp     ax,256                  ;256K
  1183.                 jae     init6
  1184.  
  1185. init_error2:    jmp     init_error
  1186.  
  1187. init6:          and     ax,0FFF0h               ;Round down to the nearest
  1188.                 mov     memory,ax               ;16K boundary
  1189.                 jmp     get_emb                 ;Loop back and try again
  1190.  
  1191. init7:          mov     emb_handle,dx           ;Save EMB handle
  1192.                 mov     ax,memory               ;Calculate the number of
  1193.                 mov     cl,4                    ;pages and save the result
  1194.                 shr     ax,cl                   ;for later
  1195.                 mov     pages,ax
  1196. ;
  1197. ; Alter the interrupt 67h vector, compute the break address, and return.
  1198. ;
  1199.                 mov     ah,09h                  ;Display the size of the
  1200.                 mov     dx,offset msg1          ;EMS memory pool
  1201.                 int     21h
  1202.                 mov     ax,memory
  1203.                 call    bin2asc
  1204.                 mov     ah,09h
  1205.                 mov     dx,offset msg2
  1206.                 int     21h
  1207.  
  1208.                 mov     ax,pages                ;Compute the address of
  1209.                 shl     ax,1                    ;the handle table
  1210.                 shl     ax,1
  1211.                 add     ax,offset page_table
  1212.                 mov     hndl_table_addr,ax      ;Save it
  1213.                 add     ax,handles              ;Compute ending address
  1214.  
  1215.                 add     ax,15                   ;Compute the segment address
  1216.                 mov     cl,4                    ;of the next higher para-
  1217.                 shr     ax,cl                   ;graph in memory for the
  1218.                 mov     bx,cs                   ;page frame address
  1219.                 add     ax,bx
  1220.  
  1221.                 mov     page_frame,ax           ;Save page frame address
  1222.                 add     ax,1000h                ;Add 1000h for break address
  1223.                 mov     word ptr es:[di+14],0   ;Store the break address in
  1224.                 mov     word ptr es:[di+16],ax  ;the request header
  1225.  
  1226.                 xor     ax,ax                   ;Grab the INT 67h vector
  1227.                 mov     es,ax
  1228.                 cli
  1229.                 mov     word ptr es:[19Ch],offset int67h
  1230.                 mov     word ptr es:[19Eh],cs
  1231.                 sti
  1232.                 ret
  1233. init            endp
  1234.  
  1235. ;****************************************************************************
  1236. ; FINDCHAR advances SI to the next non-white-space character. On return,
  1237. ; carry set indicates EOL was encountered.
  1238. ;****************************************************************************
  1239.  
  1240. findchar        proc    near
  1241.                 lodsb                           ;Get the next character
  1242.                 cmp     al,09h                  ;Loop if tab
  1243.                 je      findchar
  1244.                 cmp     al,20h                  ;Loop if space
  1245.                 je      findchar
  1246.                 cmp     al,2Ch                  ;Loop if comma
  1247.                 je      findchar
  1248.                 dec     si                      ;Point SI to the character
  1249.                 cmp     al,0Dh                  ;Exit with carry set if end
  1250.                 je      eol                     ;of line is reached
  1251.                 cmp     al,0Ah
  1252.                 je      eol
  1253.  
  1254.                 clc                             ;Clear carry and exit
  1255.                 ret
  1256.  
  1257. eol:            stc                             ;Set carry and exit
  1258.                 ret
  1259. findchar        endp
  1260.  
  1261. ;****************************************************************************
  1262. ; FINDDELIM advances SI to the next white-space character. On return,
  1263. ; carry set indicates EOL was encountered.
  1264. ;****************************************************************************
  1265.  
  1266. finddelim       proc    near
  1267.                 lodsb                           ;Get the next character
  1268.                 cmp     al,09h                  ;Exit if tab
  1269.                 je      findchar
  1270.                 cmp     al,20h                  ;Exit if space
  1271.                 je      fd_exit
  1272.                 cmp     al,2Ch                  ;Exit if comma
  1273.                 je      fd_exit
  1274.                 cmp     al,0Ah                  ;Exit if line feed
  1275.                 je      fd_eol
  1276.                 cmp     al,0Dh                  ;Loop back for more if end
  1277.                 jne     finddelim               ;of line isn't reached
  1278.  
  1279. fd_eol:         dec     si                      ;Set carry and exit
  1280.                 stc
  1281.                 ret
  1282.  
  1283. fd_exit:        dec     si                      ;Clear carry and exit
  1284.                 clc
  1285.                 ret
  1286. finddelim       endp
  1287.  
  1288. ;****************************************************************************
  1289. ; ASC2BIN converts a decimal number entered in ASCII form into a binary
  1290. ; value in AX. Carry set on return indicates that an error occurred in
  1291. ; the conversion.
  1292. ;****************************************************************************
  1293.  
  1294. asc2bin         proc    near
  1295.                 xor     ax,ax                   ;Initialize registers
  1296.                 xor     bx,bx
  1297.                 mov     cx,10
  1298.  
  1299. a2b_loop:       mov     bl,[si]                 ;Get a character
  1300.                 inc     si
  1301.                 cmp     bl,20h                  ;Exit if space
  1302.                 je      a2b_exit
  1303.                 cmp     bl,2Ch                  ;Exit if comma
  1304.                 je      a2b_exit
  1305.                 cmp     bl,0Dh                  ;Exit if carriage return
  1306.                 je      a2b_exit
  1307.                 cmp     bl,0Ah                  ;Exit if line feed
  1308.                 je      a2b_exit
  1309.  
  1310.                 cmp     bl,"0"                  ;Error if character is not
  1311.                 jb      a2b_error               ;a number
  1312.                 cmp     bl,"9"
  1313.                 ja      a2b_error
  1314.  
  1315.                 mul     cx                      ;Multiply the value in AX by
  1316.                 jc      a2b_error               ;10 and exit on overflow
  1317.                 sub     bl,30h                  ;Convert ASCII to binary
  1318.                 add     ax,bx                   ;Add latest value to AX
  1319.                 jnc     a2b_loop                ;Loop back for more if sum
  1320.                                                 ;is less than 65,535
  1321.  
  1322. a2b_error:      dec     si                      ;Set carry and exit
  1323.                 stc
  1324.                 ret
  1325.  
  1326. a2b_exit:       dec     si                      ;Clear carry and exit
  1327.                 clc
  1328.                 ret
  1329. asc2bin         endp
  1330.  
  1331. ;****************************************************************************
  1332. ; BIN2ASC converts a binary value in AX to ASCII form and displays it.
  1333. ;****************************************************************************
  1334.  
  1335. bin2asc         proc    near
  1336.                 mov     bx,10                   ;Initialize divisor word and
  1337.                 xor     cx,cx                   ;digit counter
  1338. b2a1:           inc     cx                      ;Increment digit count
  1339.                 xor     dx,dx                   ;Divide by 10
  1340.                 div     bx
  1341.                 push    dx                      ;Save remainder on stack
  1342.                 or      ax,ax                   ;Loop until quotient is zero
  1343.                 jnz     b2a1
  1344. b2a2:           pop     dx                      ;Retrieve a digit from stack
  1345.                 add     dl,30h                  ;Convert it to ASCII
  1346.                 mov     ah,2                    ;Display it
  1347.                 int     21h
  1348.                 loop    b2a2                    ;Loop until done
  1349.                 ret
  1350. bin2asc         endp
  1351.  
  1352. code            ends
  1353.                 end
  1354.